package pers.cz.mybatis.shard;

import pers.cz.obj.ObjectUtils;
import pers.cz.session.ContextHolder;
import pers.cz.session.RequestContext;
import pers.cz.spring.SpringContextUtil;
import pers.cz.sql.SqlParserTool;
import pers.cz.utils.PartitionUtil;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: PostGirl-panent
 * @description: ShardingPlugin
 * @author: Cheng Zhi
 * @create: 2021-12-28 16:19
 **/
@Intercepts(@Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {Connection.class,Integer.class}
))
public class ShardingPlugin implements Interceptor {

    Logger log = LoggerFactory.getLogger(ShardingPlugin.class);

    private long time;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        // 1、通过StatementHandler获取执行的sql
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        ParameterHandler parameterHandler = statementHandler.getParameterHandler();
        Object parameterObject = parameterHandler.getParameterObject();
        Map<String, Object[]> fieldNameAndValues = new HashMap<>();
        if (parameterObject != null) {
            // 获取对象属性
            Map<String, Object> fieldNameAndValue = new HashMap<>();
            ObjectUtils.getFieldNameAndValue(parameterObject, fieldNameAndValue);

            for (String key : fieldNameAndValue.keySet()) {
                Object[] objs = new Object[] {fieldNameAndValue.get(key)};
                fieldNameAndValues.put(key, objs);
            }
        }

        String sqlBefore = boundSql.getSql();
        String tableName = SqlParserTool.getSingleTableName(sqlBefore);
        // 如果没有分表字段，可直接在这里指定
        RequestContext requestContext = ContextHolder.getRequestContext();
        if (requestContext != null && requestContext.get("SO_NBR") != null) {
            Object so_nbr = requestContext.get("SO_NBR");
            fieldNameAndValues.put("SO_NBR", new Object[] {so_nbr});
        }
        // 更新后的sql
        if (sqlBefore.contains(tableName) && fieldNameAndValues.size() > 0) {
            // 获取sql条件中的字段名和对应的字段值。
            PartitionUtil bean = SpringContextUtil.getBean(PartitionUtil.class);
            if (bean != null) {
                String newTableName = bean.getTableName(tableName, fieldNameAndValues, null);
                if (newTableName != null) {
                    String sqlAfter = sqlBefore.replaceAll(tableName, newTableName);
                    // 通过反射替换boundSql中的sql
                    Field sqlField = boundSql.getClass().getDeclaredField("sql");
                    sqlField.setAccessible(true);
                    sqlField.set(boundSql, sqlAfter);
                }
            }

        }
        //metaStmtHandler.setValue("delegate.boundSql.sql", sql);

        // 创建一个新的执行器
        //Invocation invocationNew = new Invocation(invocation.getTarget(), );
        Object proceed = invocation.proceed();

        return proceed;
    }


}
